#define _USE_MATH_DEFINES
#include <math.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include<algorithm>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <iostream>
#include "NamedFingers.h"
#include "background_codebook_header.h"

#define BGR2HLS CV_BGR2HLS
#define HLS2BGR CV_HLS2BGR
#define NSAMPLES 9
#define PI 3.14159


using namespace cv;
using namespace std;
class HandTrack
{
public:
	HandTrack(void);
	~HandTrack(void);
	void nameWindows();
	void initVideoCapture();
	bool videoFrameCapture();
	void upSampleFrame();
	void downSampleFrame();
	void updateModel();
	void init_windows();
	void update();
	void initAndUpdateCodeBook();
	void initCodeBookMaskImages();
	void initCodeBookModel();
	void findContour(Rect& box, Mat& frame);
	void findConvexHull();
	void findFingers();
	bool frameCapture();
	bool isCodeBookInitialized;
	void extractContour();
	void draw_fingers();
	void updateCodeBookValues(char c);

	void draw_frame();
	vector<vector<Point>> contours;
	CvSeq* hull;
	Mat mask;
	int frameNumber;
	void drawMask();
	/**
	filter and threshold.
	@param ht. the handTrack object.
	*/
	char *window_mask;

private:
	// globals
	int MIN_FINGER_DEPTH;
	int MAX_FINGER_ANGLE;   // degrees
	Rect bRect;
	int nrOfFingers;
	Mat iMaskCodebook;
	int nrOfDefects;
	int fontFace;
	Scalar lowerVal;
	Mat yCrCbImg;
	
	int imgLen;
	int nrFrames ;
	int nrFramesToLearnBG;

	Mat iMaskCodeBook;
	Mat iMaskCodeBookCC;
	Scalar upperVal;
	VideoCapture videoCap;
	map<int, int> namedFingers;
	char* window_output;

	char* window_foreground;
	char* window_temp_frame;
	
	int findBiggestContour();

	// globals
	Point cogPt;       // center of gravity (COG) of contour
	int contourAxisAngle;     
	//vector<vector<Point>> contours;
	codeBook* cbModel;
	int num_defects;
	double hand_radius;
	double min_area;
	
	Mat foreground;
	Mat frame;
	vector<Mat> vectorMats;
	int backgroundframe;
	double max_area;
	CvCapture* capture;
	vector<vector<int> >hullI;
	vector<vector<Point> >hullP;
	vector<vector<Vec4i> > defects;	
	vector<Point> fingerTips;
	
	int MAX_THUMB;
	int MIN_THUMB;

private:
	void drawFingerTips();
	bool detectIsHandContour();
	void getFingerTips(int index);
	void checkForOneFinger(int index);
	int nrSamples;
	
	void removeRedundantEndPoints(vector<Vec4i> newDefects, int index);
	
	void initMyCodeBookModel();
	void initMyCodeBookMaskImages();
	float getAngle(Point a, Point b, Point c);
	void drawHandContours(int contourIdx);
	void initContourAndHullVectors();
	
	void extractContourInfo(int index);
	float getDistanceBetweenPoints(Point a, Point b);
	void filterDefects(int index);
	void initial_filter_image(int initFilterTime);
	int computeAngleBetween(Point pt1, Point pt2,Point pt3);

	double convertToDegrees(float theta);
	int calculateTilt(double m11, double m20, double m02);
	void labelThumbIndex();
	void initROIForFrame(Rect& rect);
	void labelUnknowns();

	codeBook* createCodeBookModel();
	int angleToMajor(Point fingerTip);//angle to center of the gravity
	int maxMod[CHANNELS];	//Add these (possibly negative) number onto max 
	
	bool channelsActive[CHANNELS];		//This sets what channels should be adjusted for background bounds
};
